package sys

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/vueadmin/app/admin/internal/svc"
	"github.com/vueadmin/utils"
	"github.com/vueadmin/utils/conv"
	"github.com/vueadmin/utils/response"
	"gorm.io/gorm"
	"strings"
	"sync"
)

const (
	APIURL   = "http://127.0.0.1:8080"
	APITOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJWlkIjoiVUdJT0Q1NTA4N0Q5IiwiaWF0IjoxNzE1NDc3Mzc1fQ.NWsyahfi70Nz0blepwtrgwTAo4UBsxbe0YVvjkErwJU"
)

var wg sync.WaitGroup

var ApiPost = new(apiPost)

type apiPost struct {
	menu        Menu
	application Application
	field       []Field
	action      []Action
	token_field []string
}

type createProjectReq struct {
	AppId int `form:"app_id" json:"app_id" validate:"required" label:"app_id"` //appid
}

type createApiReq struct {
	Id     interface{} `form:"id" json:"id,optional"`                                      //id
	MenuId int         `form:"menu_id" json:"menu_id" validate:"required" label:"menu_id"` //appid
}

// 创建api项目
func (p apiPost) CreateDocProject(c *gin.Context, svcCtx *svc.ServiceContext) {
	var req createProjectReq
	if err := utils.BindAndValid(c, &req); err != nil {
		response.Fail(c, err.Error())
		return
	}
	var data map[string]interface{}
	if err := svcCtx.Db.Model(&Application{}).Where("app_id = ?", req.AppId).First(&data).Error; err != nil {
		response.Err(c, err)
		return
	}
	if conv.Int(data["app_type"]) != 2 {
		response.Fail(c, "仅支持api应用!")
		return
	}
	if !conv.IsEmpty(data["project_id"]) {
		response.Fail(c, "接口文档项目已经创建!")
		return
	}
	header := make(map[string]string)
	header["Content-Type"] = "application/json"
	header["api-token"] = APITOKEN

	res := utils.NewHttpRequest().Request("GET", "https://openapi.apipost.cn/open/team/list?is_readonly=1", nil, header).ParseJson()
	if value, ok := res["code"]; ok && conv.Int(value) != 10000 {
		response.Fail(c, conv.String(res["msg"]))
		return
	}

	projectInfo := make(map[string]string)
	projectInfo["name"] = conv.String(data["application_name"])
	projectInfo["intro"] = conv.String(data["application_name"])
	projectInfo["team_id"] = conv.String(res["data"].([]interface{})[0].(map[string]interface{})["team_id"])

	ret := utils.NewHttpRequest().Request("POST", "https://openapi.apipost.cn/open/project/create", strings.NewReader(conv.String(projectInfo)), header).ParseJson()
	if value, ok := res["code"]; ok && conv.Int(value) != 10000 {
		response.Fail(c, conv.String(res["msg"]))
		return
	}
	if err := svcCtx.Db.Model(&Application{}).Where("app_id = ?", req.AppId).Update("project_id", ret["data"].(map[string]interface{})["project_id"]).Error; err != nil {
		response.Err(c, err)
		return
	}
	response.Success(c, "操作成功", nil)
}

// 生成文档
func (p apiPost) CreateApiDoc(c *gin.Context, svcCtx *svc.ServiceContext) {
	var req createApiReq
	if err := utils.BindAndValid(c, &req); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if err := svcCtx.Db.Where("menu_id = ?", req.MenuId).Find(&p.menu).Error; err != nil {
		response.Err(c, err)
		return
	}
	if err := svcCtx.Db.Where("app_id = ?", p.menu.AppId).Find(&p.application).Error; err != nil {
		response.Err(c, err)
		return
	}
	if conv.IsEmpty(p.application.ProjectId) {
		response.Fail(c, "项目id不能为空")
		return
	}
	actionQuery := svcCtx.Db.Where("menu_id = ?", req.MenuId)
	if !conv.IsEmpty(req.Id) {
		actionQuery = actionQuery.Where("id in ?", req.Id)
	}
	actionQuery = actionQuery.Where("id not in ?", []int{52, 53})
	if err := actionQuery.Find(&p.action).Error; err != nil {
		response.Err(c, err)
		return
	}
	if err := svcCtx.Db.Where("menu_id = ?", req.MenuId).Find(&p.field).Error; err != nil {
		response.Err(c, err)
		return
	}
	for _, v := range p.field {
		if v.Type == 30 {
			p.token_field = append(p.token_field, v.Field)
		}
	}
	for k, v := range p.action {
		wg.Add(1)
		go func(k int, v Action) {
			defer wg.Done()
			res := p.doApi(svcCtx, conv.Uint(k), v)
			if value, ok := res["code"]; ok && conv.Int(value) == 12000 {
				response.Fail(c, conv.String(res["msg"]))
				return
			}
			if value, ok := res["code"]; ok && conv.Int(value) == 11095 {
				svcCtx.Db.Model(&Field{}).Where("id = ?", v.Id).Update("version", gorm.Expr("version + ?", 1))
				v.Version = v.Version + 1
				p.doApi(svcCtx, conv.Uint(k), v)
			}
		}(k, v)
	}
	wg.Wait()
	response.Success(c, "生成成功", nil)
}

func (p apiPost) doApi(svcCtx *svc.ServiceContext, k uint, v Action) map[string]interface{} {
	data := make(map[string]interface{})
	data["target_id"] = fmt.Sprintf("%d_%s_%d_%d", v.Id, p.application.ProjectId, p.menu.MenuId, v.Version)
	data["project_id"] = p.application.ProjectId
	data["parent_id"] = "0"
	data["mark"] = "complated"
	data["target_type"] = "api"
	data["name"] = fmt.Sprintf("%s-%s", p.menu.Title, v.Name)
	data["method"] = "post"
	data["sort"] = conv.String(p.menu.MenuId*100000 + v.Id*100 + k)

	var parameter []map[string]interface{}
	if v.SmsAuth == 1 {
		parameter = append(parameter, map[string]interface{}{
			"description": "短信验证码",
			"is_checked":  1,
			"key":         "verify",
			"type":        "text",
			"not_null":    1,
			"field_type":  "String",
			"value":       "123456",
		}, map[string]interface{}{
			"description": "验证id,发送短信时返回参数",
			"is_checked":  1,
			"key":         "verify_id",
			"type":        "text",
			"not_null":    1,
			"field_type":  "String",
			"value":       "57bea93d622080923f3a51",
		}, map[string]interface{}{
			"description": "手机号,必须同接收短信手机号一致",
			"is_checked":  1,
			"key":         "mobile",
			"type":        "text",
			"not_null":    1,
			"field_type":  "String",
			"value":       "135450280000",
		})
	}
	if v.ImgAuth == 1 {
		parameter = append(parameter, map[string]interface{}{
			"description": "图片验证码",
			"is_checked":  1,
			"key":         "captcha",
			"type":        "text",
			"not_null":    1,
			"field_type":  "String",
			"value":       "0f5q",
		}, map[string]interface{}{
			"description": "验证码id",
			"is_checked":  1,
			"key":         "key_id",
			"type":        "text",
			"not_null":    1,
			"field_type":  "String",
			"value":       "57bea93d622080923f3a51",
		})
	}

	switch v.Type {
	case 1:
		parameter = append(parameter, map[string]interface{}{
			"description": "每页显示条数，默认为1",
			"is_checked":  0,
			"key":         "limit",
			"type":        "text",
			"not_null":    0,
			"field_type":  "Number",
			"value":       "1",
		}, map[string]interface{}{
			"description": "页码，默认为20",
			"is_checked":  0,
			"key":         "page",
			"type":        "text",
			"not_null":    0,
			"field_type":  "Number",
			"value":       v.Pagesize,
		})
		for _, val := range p.field {
			if val.SearchType == 1 || val.SearchType == 2 {
				parameter = append(parameter, map[string]interface{}{
					"description": p.getDescription(val),
					"is_checked":  0,
					"key":         val.Field,
					"type":        "text",
					"not_null":    0,
					"field_type":  p.getSearchDataType(val),
					"value":       p.getSearchDefaultValue(svcCtx, val),
				})
			}
		}
	case 2:
		if len(v.Fields) > 1 {
			for _, n := range v.Fields {
				for _, val := range p.field {
					if val.Field == n && val.PostStatus && !conv.IsValueInList(conv.String(val.Type), []string{"11", "12", "30"}) {
						parameter = append(parameter, map[string]interface{}{
							"description": p.getDescription(val),
							"is_checked":  1,
							"key":         val.Field,
							"type":        "text",
							"not_null":    p.getRequired(val),
							"field_type":  p.getDataType(val),
							"value":       p.getPostDefaultValue(svcCtx, val),
						})
					}
				}
			}
		} else {
			for _, val := range p.field {
				if val.PostStatus && !conv.IsValueInList(conv.String(val.Type), []string{"11", "12", "30"}) {
					parameter = append(parameter, map[string]interface{}{
						"description": p.getDescription(val),
						"is_checked":  1,
						"key":         val.Field,
						"type":        "text",
						"not_null":    p.getRequired(val),
						"field_type":  p.getDataType(val),
						"value":       p.getPostDefaultValue(svcCtx, val),
					})
				}
			}
		}
	case 3:
		if v.ApiAuth == 0 || !conv.IsValueInList(conv.String(p.menu.MenuId), p.token_field) {
			parameter = append(parameter, map[string]interface{}{
				"description": "编号",
				"is_checked":  1,
				"key":         p.menu.Pk,
				"type":        "text",
				"not_null":    1,
				"field_type":  "Number",
				"value":       "1",
			})
		}
		if len(v.Fields) > 1 {
			for _, n := range v.Fields {
				for _, val := range p.field {
					if val.Field == n && val.PostStatus && !conv.IsValueInList(conv.String(val.Type), []string{"7", "11", "12", "30"}) {
						parameter = append(parameter, map[string]interface{}{
							"description": p.getDescription(val),
							"is_checked":  1,
							"key":         val.Field,
							"type":        "text",
							"not_null":    p.getRequired(val),
							"field_type":  p.getDataType(val),
							"value":       p.getPostDefaultValue(svcCtx, val),
						})
					}
				}
			}
		} else {
			for _, val := range p.field {
				if val.PostStatus && !conv.IsValueInList(conv.String(val.Type), []string{"7", "11", "12", "30"}) {
					parameter = append(parameter, map[string]interface{}{
						"description": p.getDescription(val),
						"is_checked":  1,
						"key":         val.Field,
						"type":        "text",
						"not_null":    p.getRequired(val),
						"field_type":  p.getDataType(val),
						"value":       p.getPostDefaultValue(svcCtx, val),
					})
				}
			}
		}
	case 4:
		if v.ApiAuth == 0 || !conv.IsValueInList(conv.String(p.menu.MenuId), p.token_field) {
			parameter = append(parameter, map[string]interface{}{
				"description": "编号",
				"is_checked":  1,
				"key":         p.menu.Pk,
				"type":        "text",
				"not_null":    1,
				"field_type":  "Number",
				"value":       "1",
			})
		}
	case 5:
		if len(v.SearchField) > 1 {
			for _, val := range v.SearchField {
				if !conv.IsEmpty(val) {
					for _, n := range p.field {
						if conv.String(val) == conv.String(n.Field) {
							parameter = append(parameter, map[string]interface{}{
								"description": p.getDescription(n),
								"is_checked":  1,
								"key":         n.Field,
								"type":        "text",
								"not_null":    p.getRequired(n),
								"field_type":  p.getDataType(n),
								"value":       p.getPostDefaultValue(svcCtx, n),
							})
						}
					}
				}
			}
		} else {
			if v.ApiAuth == 0 || !conv.IsValueInList(conv.String(p.menu.MenuId), p.token_field) {
				parameter = append(parameter, map[string]interface{}{
					"description": "编号",
					"is_checked":  1,
					"key":         p.menu.Pk,
					"type":        "text",
					"not_null":    1,
					"field_type":  "Number",
					"value":       "1",
				})
			}
		}

	case 6:
		if v.ApiAuth == 0 || !conv.IsValueInList(conv.String(p.menu.MenuId), p.token_field) {
			parameter = append(parameter, map[string]interface{}{
				"description": "编号",
				"is_checked":  1,
				"key":         p.menu.Pk,
				"type":        "text",
				"not_null":    1,
				"field_type":  "Number",
				"value":       "1",
			})
		}
		parameter = append(parameter, map[string]interface{}{
			"description": "密码",
			"is_checked":  1,
			"key":         "password",
			"type":        "text",
			"not_null":    1,
			"field_type":  "String",
			"value":       "123456",
		})
	case 7:
		if v.ApiAuth == 0 || !conv.IsValueInList(conv.String(p.menu.MenuId), p.token_field) {
			parameter = append(parameter, map[string]interface{}{
				"description": "编号",
				"is_checked":  1,
				"key":         p.menu.Pk,
				"type":        "text",
				"not_null":    1,
				"field_type":  "Number",
				"value":       "1",
			})
		}
	case 8:
		if v.ApiAuth == 0 || !conv.IsValueInList(conv.String(p.menu.MenuId), p.token_field) {
			parameter = append(parameter, map[string]interface{}{
				"description": "编号",
				"is_checked":  1,
				"key":         p.menu.Pk,
				"type":        "text",
				"not_null":    1,
				"field_type":  "Number",
				"value":       "1",
			})
		}
		for _, val := range p.field {
			if val.Field == v.Fields[0] {
				parameter = append(parameter, map[string]interface{}{
					"description": p.getDescription(val),
					"is_checked":  1,
					"key":         val.Field,
					"type":        "text",
					"not_null":    1,
					"field_type":  p.getDataType(val),
					"value":       "5",
				})
			}
		}
	case 9:
		if v.ApiAuth == 0 || !conv.IsValueInList(conv.String(p.menu.MenuId), p.token_field) {
			parameter = append(parameter, map[string]interface{}{
				"description": "编号",
				"is_checked":  1,
				"key":         p.menu.Pk,
				"type":        "text",
				"not_null":    1,
				"field_type":  "Number",
				"value":       "1",
			})
		}
		for _, val := range p.field {
			if val.Field == v.Fields[0] {
				parameter = append(parameter, map[string]interface{}{
					"description": p.getDescription(val),
					"is_checked":  1,
					"key":         val.Field,
					"type":        "text",
					"not_null":    1,
					"field_type":  p.getDataType(val),
					"value":       "5",
				})
			}
		}
	case 50:
		other_config := v.OtherConfig
		if conv.Int(other_config["login_type"]) == 1 {
			parameter = append(parameter, map[string]interface{}{
				"description": "登录账号",
				"is_checked":  1,
				"key":         conv.String(other_config["userField"]),
				"type":        "text",
				"not_null":    1,
				"field_type":  "String",
				"value":       "zhangsan",
			}, map[string]interface{}{
				"description": "登录密码",
				"is_checked":  1,
				"key":         conv.String(other_config["pwdField"]),
				"type":        "text",
				"not_null":    1,
				"field_type":  "String",
				"value":       "123456",
			})
		} else {
			if v.SmsAuth == 0 {
				parameter = append(parameter, map[string]interface{}{
					"description": "登录手机号",
					"is_checked":  1,
					"key":         conv.String(other_config["smsField"]),
					"type":        "text",
					"not_null":    1,
					"field_type":  "String",
					"value":       "13545028000",
				})
			}
		}
	case 51:
		parameter = append(parameter, map[string]interface{}{
			"description": "手机号",
			"is_checked":  1,
			"key":         "mobile",
			"type":        "text",
			"not_null":    1,
			"field_type":  "String",
			"value":       "13545028000",
		})
	}
	headerParameter := []map[string]interface{}{}
	if v.ApiAuth == 1 {
		headerParameter = append(headerParameter, map[string]interface{}{
			"description": "token值",
			"is_checked":  1,
			"key":         "Authorization",
			"type":        "text",
			"not_null":    1,
			"field_type":  "String",
			"value":       "1613887bd772e2b67c57bea93d622080923f3a51",
		})
	}
	description := ""
	if v.Type == 50 {
		description = fmt.Sprintf("说明:token有效期%d秒", 7200)
	}
	data["request"] = map[string]interface{}{
		"url": fmt.Sprintf("%s/%s/%s/%s", APIURL, p.application.AppDir, p.menu.ControllerName, v.ActionName),
		"auth": map[string]interface{}{
			"type": "noauth",
		},
		"header": map[string]interface{}{
			"parameter": headerParameter,
		},
		"event": map[string]interface{}{
			"pre_script": "",
			"test":       "",
		},
		"description": description,
		"body": map[string]interface{}{
			"mode":      "urlencoded",
			"parameter": parameter,
			"raw":       "",
			"raw_para":  []map[string]interface{}{},
			"raw_schema": map[string]interface{}{
				"type": "object",
			},
		},
	}

	raw := ""
	switch v.Type {
	case 1:
		raw = "{\"status\":200,\"data\":{\"total\":10,\"per_page\":20,\"current_page\":1,\"last_page\":1,\"data\":[]}}"
	case 2:
		raw = "{\"status\":200,\"data\":1,\"msg\":\"添加成功\"}"
	case 3:
		raw = "{\"status\":200,\"msg\":\"修改成功\"}"
	case 4:
		raw = "{\"status\":200,\"msg\":\"操作成功\"}"
	case 5:
		raw = "{\"status\":200,\"data\":{}}"
	case 6:
		raw = "{\"status\":200,\"msg\":\"操作成功\"}"
	case 7:
		raw = "{\"status\":200,\"msg\":\"操作成功\"}"
	case 8:
		raw = "{\"status\":200}"
	case 9:
		raw = "{\"status\":200}"
	case 50:
		raw = "{\"status\":200,\"data\":{},\"token\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJjbGllbnQudnVlYWRtaW4iLCJhdWQiOiJzZXJ2ZXIudnVlYWRtaW4iLCJpYXQiOjE2OTg2NDQ1NjQuOTcyMjI3LCJuYmYiOjE2OTg2NDQ1NjQuOTcyMjI3LCJleHAiOjE2OTkwNzY1NjQuOTcyMjI3LCJ1aWQiOiJ7XCJtZW1iZV9pZFwiOjI3LFwidXNlcm5hbWVcIjpcIlxcdTczOGJcXHU0ZTk0XCIsXCJzZXhcIjoyLFwibW9iaWxlXCI6XCIxMzU0NTA5ODc2MVwiLFwicGljXCI6XCJodHRwOlxcL1xcL3Z1ZS53aHBqLnZpcFxcL3VwbG9hZHNcXC9hZG1pblxcLzIwMjEwNVxcLzYwYWY4ZDdkNDdhTAuanBnXCIsXCJlbWFpbFwiOlwiMzY3MzI3NjdAcXEuY29tXCJ9In0.lBbgBmOstAAZQX9kN_BvYUHYp3Ff-mibzmmuDVaUENc\"}"
	case 51:
		raw = "{\"status\":200,\"msg\":\"发送成功\",key:\"57bea93d622080923f3a51\"}"
	}

	var successParamter []map[string]interface{}

	switch v.Type {
	case 1:
		for _, val := range p.field {
			if val.ListShow == 1 {
				successParamter = append(successParamter, map[string]interface{}{
					"description": p.getDescription(val),
					"is_checked":  1,
					"key":         val.Field,
					"type":        "text",
					"not_null":    1,
					"field_type":  p.getDataType(val),
					"value":       "",
				})
			}
		}
	case 5:
		if len(v.Fields) > 1 {
			for _, n := range v.Fields {
				for _, val := range p.field {
					if val.Field == n {
						successParamter = append(successParamter, map[string]interface{}{
							"description": p.getDescription(val),
							"is_checked":  1,
							"key":         val.Field,
							"type":        "text",
							"not_null":    p.getRequired(val),
							"field_type":  p.getDataType(val),
							"value":       "",
						})
					}
				}
			}
		} else {
			for _, val := range p.field {
				if val.ListShow == 1 {
					successParamter = append(successParamter, map[string]interface{}{
						"description": p.getDescription(val),
						"is_checked":  1,
						"key":         val.Field,
						"type":        "text",
						"not_null":    p.getRequired(val),
						"field_type":  p.getDataType(val),
						"value":       "",
					})
				}
			}
		}
	}

	data["response"] = map[string]interface{}{
		"success": map[string]interface{}{
			"raw":       raw,
			"parameter": successParamter,
		},
	}

	header := make(map[string]string)
	header["Content-Type"] = "application/json"
	header["api-token"] = APITOKEN
	ret := utils.NewHttpRequest().Request("POST", "https://openapi.apipost.cn/open/apis/save_target", strings.NewReader(conv.String(data)), header).ParseJson()

	return ret
}

func (p apiPost) getDescription(val Field) string {
	description := ""
	if conv.IsValueInList(conv.String(val.Type), []string{"2", "3", "4", "5", "6"}) && !conv.IsEmpty(val.ItemConfig) {
		for _, v := range val.ItemConfig {
			description += conv.String(v["key"]) + "-" + conv.String(v["val"]) + ";"
		}
	}
	return strings.TrimRight(val.Title+", "+description, ",")
}

func (p apiPost) getSearchDefaultValue(svcCtx *svc.ServiceContext, val Field) string {
	data := ""
	if conv.IsValueInList(conv.String(val.Type), []string{"2", "3", "4", "5", "6"}) && conv.IsEmpty(val.Sql) {
		if !conv.IsEmpty(val.ItemConfig) && len(val.ItemConfig) > 0 {
			data = conv.String(val.ItemConfig[0]["val"])
		}
	} else if val.Type == 2 {
		data = "123456"
	} else if val.Type == 11 || val.Type == 12 {
		data = "[2023-01-01 12:00:00,2023-01-05 12:00:00]"
	} else {
		var info map[string]interface{}
		svcCtx.Db.Table("cd_" + p.menu.Tablename).Limit(1).Find(&info)
		data = conv.String(info[val.Field])
	}
	return data
}

func (p apiPost) getPostDefaultValue(svcCtx *svc.ServiceContext, val Field) string {
	data := ""
	if conv.IsValueInList(conv.String(val.Type), []string{"2", "3", "4", "5", "6"}) && conv.IsEmpty(val.Sql) {
		if !conv.IsEmpty(val.ItemConfig) && len(val.ItemConfig) > 0 {
			data = conv.String(val.ItemConfig[0]["val"])
		}
	} else if val.Type == 7 {
		data = "123456"
	} else if val.Type == 9 {
		data = "2023-01-01 12:00:00"
	} else if val.Type == 11 || val.Type == 12 {
		data = "[2023-01-01 12:00:00,2023-01-05 12:00:00]"
	} else if val.Type == 14 || val.Type == 16 {
		data = "[{\"url\":\"a.jpg\",\"name\":\"文件名称\"},{\"url\":\"b.jpg\",\"name\":\"文件名称2.jpg\"}]"
	} else if val.Type == 25 || val.Type == 26 || val.Type == 27 {
		data = "测试编辑器内容"
	} else {
		var info map[string]interface{}
		if err := svcCtx.Db.Table("cd_" + p.menu.Tablename).Limit(1).Find(&info).Error; err != nil {
			panic(err)
		}
		data = conv.String(info[val.Field])
	}
	return data
}

func (p apiPost) getSearchDataType(val Field) string {
	data := "string"
	if val.Type == 11 || val.Type == 12 {
		data = "Array"
	} else {
		if conv.IsValueInList(val.Datatype, []string{"tinyint", "int", "smallint", "longint"}) {
			data = "Number"
		} else if val.Datatype == "decimal" {
			data = "Float"
		}
	}
	return data
}

func (p apiPost) getDataType(val Field) string {
	data := "string"
	if conv.IsValueInList(val.Datatype, []string{"tinyint", "int", "smallint", "mediumint", "longint"}) {
		data = "Number"
	} else if val.Datatype == "decimal" {
		data = "Float"
	}
	return data
}

func (p apiPost) getRequired(val Field) int {
	data := 0
	if !conv.IsEmpty(val.Validate) {
		if strings.Contains(val.Validate, "required") {
			data = 1
		}
	}
	return data
}
